package org.bdware.repository.webService.service;

import com.google.gson.Gson;
import org.apache.log4j.Logger;
import org.bdware.doip.core.doipMessage.DoipMessage;
import org.bdware.doip.core.doipMessage.DoipMessageFactory;
import org.bdware.doip.core.doipMessage.DoipResponseCode;
import org.bdware.doip.endpoint.doipClient.DoipClient;
import org.bdware.doip.endpoint.doipClient.SyncDOAClient;
import org.bdware.doip.endpoint.doipServer.DoipServiceInfo;
import org.bdware.irp.client.GlobalIrpClient;
import org.bdware.irp.exception.IrpClientException;
import org.bdware.repository.handler.BDRepositoryHandler;
import org.bdware.repository.main.BDRepository;
import org.bdware.repository.storage.BDRepoStorage;
import org.bdware.repository.storage.RemoteReg;
import org.bdware.repository.webService.dto.Stat;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;

@Service
public class RepositoryService {
    BDRepositoryHandler handler = BDRepository.getRepositoryHandler();
    DoipServiceInfo doipInfo = BDRepository.getInfo();
    BDRepoStorage store = BDRepository.getStore();
    SyncDOAClient doaClient;
    static Logger logger = Logger.getLogger(RepositoryService.class);

    public RepositoryService() throws InterruptedException {
        int count = 0;
        while (handler == null || doipInfo == null) {
            logger.info("wait for DOIP Service initialization");
            Thread.sleep(1000);
            if (count++ > 5) break;
        }
        if (handler == null || doipInfo == null) {
            logger.error("DOIP Service not initialized.");
        }
    }

    public String getRepoInfo() {
        return doipInfo.toJson();
    }

    public Collection<RemoteReg> getRemoteRegistry() {
        return handler.getRemoteRegs().values();
    }

    public boolean addRemoteRegistry(String regID, int level) throws IrpClientException {
        logger.info("==add reg: " + regID + " ," + level);
        DoipClient doipClient = getDoaClient().getDoipClient(regID);
        RemoteReg toAdd = new RemoteReg(regID, doipClient.getRepoUrl(), level);
        logger.info("now regs: " + new Gson().toJson(handler.getRemoteRegs()));
        if (handler.getRemoteRegs().containsKey(regID)) {
            RemoteReg r = handler.getRemoteRegs().get(regID);
            //原本以引接方式接入，现在要退出
            if (r.equals(toAdd) && r.indexLevel == 1 && toAdd.indexLevel != 1) {
                DoipMessage req = new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(regID, "Op.Quit")
                        .addAttributes("repoID", doipInfo.id)
                        .addAttributes("repoUrl", doipInfo.listenerInfos.get(0).url)
                        .create();
                DoipMessage resp = getDoaClient().sendRaw(req, regID);
                logger.debug("-quit response code: " + resp.header.parameters.response.getName());
                logger.debug("-quit response body: " + resp.body.getDataAsJsonString());
                if (resp.header.parameters.response == DoipResponseCode.Success) {
                    handler.addRemoteRegistry(toAdd);
                    return true;
                }
            } else if (r.indexLevel == toAdd.indexLevel) return true;
        }
        if (level == 1) {
            DoipMessage req = new DoipMessageFactory.DoipMessageBuilder()
                    .createRequest(regID, "Op.Join")
                    .addAttributes("repoID", doipInfo.id)
                    .addAttributes("repoUrl", doipInfo.listenerInfos.get(0).url)
                    .create();
            logger.info(new Gson().toJson(req));
            DoipMessage resp = getDoaClient().sendRaw(req, regID);
            logger.info("-join response code: " + resp.header.parameters.response.getName());
            logger.info("-join response body: " + resp.body.getDataAsJsonString());
            if (resp.header.parameters.response == DoipResponseCode.Success) {
                handler.addRemoteRegistry(new RemoteReg(regID, doipClient.getRepoUrl(), level));
                return true;
            }
            logger.warn("add remote registry failed: " + resp.header.parameters.response.getName());
            return false;
        } else {
            handler.addRemoteRegistry(new RemoteReg(regID, doipClient.getRepoUrl(), level));
            return true;
        }
    }

    public boolean testRemoteRegConnection(String regID) throws IrpClientException {
        DoipMessage msg = getDoaClient().hello(regID);
        logger.info("test connection: " + msg);
        return msg.header.parameters.response == DoipResponseCode.Success;
    }

    private SyncDOAClient getDoaClient() throws IrpClientException {
        if (doaClient == null)
            doaClient = new SyncDOAClient(2000);
        return doaClient;
    }

    public Stat getStat() {
        return store.getStat();
    }

}
